﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using VAdvantage.Utility;
using VAdvantage.DataBase;
using VAdvantage.Logging;
using System.Reflection;
using System.Data;
using System.Data.SqlClient;


namespace VAdvantage.ProcessEngine
{
    public abstract class SvrProcess : ProcessCall
    {

        private Ctx ctxContext = Utility.Envs.GetCtx();
        private ProcessInfo _pi;

        private VAdvantage.Model.PO objPO = null;

        protected static String msgSaveErrorRowNotFound = "@SaveErrorRowNotFound@";
        protected static String msgInvalidArguments = "@InvalidArguments@";
        private Trx _trx;


        /**	Logger							*/
       protected internal VLogger log = null;

        public SvrProcess()
        {
            if (log == null)
                log = VLogger.GetVLogger(this.GetType().FullName);
            //nothing to process in constructor
        }
       

        public bool StartProcess(Utility.Ctx ctx, ProcessInfo pi, Trx trx)
        {
            //  Preparation
            ctxContext = ctx == null ? Utility.Envs.GetCtx() : ctx;
            _pi = pi;

            bool localTrx = _trx == null;
            if (localTrx)
            {

            }

            String msg = null;
            bool success = true;
            try
            {
                Lock();
                Prepare();
                msg = DoIt();
            }
            catch (Exception e)
            {
                msg = e.Message;
                if (msg == null)
                    msg = e.ToString();
                if (e.Message != null)
                    log.Log(Level.SEVERE, msg);
                else if (VLogMgt.IsLevelFiner())
                    log.Log(Level.WARNING, msg);
                else
                    log.Warning(msg);
                success = false;
            }
            //if (_trx != null)
            //    if (localTrx)
            //    {
            //        if (success)
            //            _trx.Commit();
            //        else
            //            _trx.Rollback();
            //        _trx.Close();
            //        _trx = null;
            //    }
            //	Parse Variables
            msg = Msg.ParseTranslation(ctx, msg);
            _pi.SetSummary(msg, !success);
            ProcessInfoUtil.SaveLogToDB(_pi);
            //Unlock();
            return success;
        }

        /// <summary>
        /// abstract function Prepare
        /// </summary>
        abstract protected void Prepare();
        /// <summary>
        /// abstract function DoIt
        /// </summary>
        /// <returns></returns>
        abstract protected string DoIt();


        public ProcessInfo GetProcessInfo()
        {
            return _pi;
        }


        private void Lock()
        {
            log.Fine("AD_PInstance_ID=" + _pi.GetAD_PInstance_ID());
            DB.ExecuteQuery("UPDATE AD_PInstance SET IsProcessing='Y' WHERE AD_PInstance_ID="
                + _pi.GetAD_PInstance_ID());		//	outside trx
        }   //  lock

        /// <summary>
        /// Unlock Process Instance.
        /// Update Process Instance DB and write option return message
        /// </summary>
        private void Unlock()
        {
            MPInstance mpi = new MPInstance(Utility.Envs.GetContext(), _pi.GetAD_PInstance_ID(), null);
            if (mpi.Get_ID() == 0)
            {
                log.Log(Level.SEVERE, "Did not find PInstance " + _pi.GetAD_PInstance_ID());
                return;
            }
            mpi.SetIsProcessing(false);
            mpi.SetResult(_pi.IsError());
            mpi.SetErrorMsg(_pi.GetSummary());
            mpi.Save();
            log.Fine(mpi.ToString());
        }



        /// <summary>
        /// Commit
        /// </summary>
        protected void Commit()
        {
            if (_trx != null)
            {
                _trx.Commit();
            }
        }

        /// <summary>
        /// Rollback
        /// </summary>
        protected void Rollback()
        {
            if (_trx != null)
                _trx.Rollback();
        }	//	rollback

        /// <summary>
        /// Return the main transaction of the current process.
        /// </summary>
        /// <returns>the transaction name</returns>
        public String Get_TrxName()
        {
            if (_trx != null)
                return _trx.GetTrxName();
            return null;
        }

        /// <summary>
        /// Return the main transaction of the current process.
        /// </summary>
        /// <returns>the transaction</returns>
        protected Trx Get_Trx()
        {
            return _trx;
        }	//	get_Trx

        public void AddLog(int id, DateTime? date, Decimal? number, String msg)
        {
            if (_pi != null)
                _pi.AddLog(id, date, number, msg);
            log.Info(id + " - " + date + " - " + number + " - " + msg);
        }	//	addLog

        public void AddLog(String msg)
        {
            if (msg != null)
                AddLog(0, DateTime.MinValue, null, msg);
        }	//	addLog


        /// <summary>
        /// Gets the parameter
        /// </summary>
        /// <returns></returns>
        protected ProcessInfoParameter[] GetParameter()
        {
            ProcessInfoParameter[] retValue = _pi.GetParameter();
            if (retValue == null || retValue.Length == 0)
            {
                ProcessInfoUtil.SetParameterFromDB(_pi);
                retValue = _pi.GetParameter();
            }
            return retValue;
        }

        /// <summary>
        /// DO function finally call the class and execute the method required with params
        /// </summary>
        /// <param name="className">Name of the class</param>
        /// <param name="methodName">Name of the Method</param>
        /// <param name="args">Arguements to be passed in a method</param>
        /// <returns>Object</returns>
        public Object DoIt(String className, String methodName, Object[] args)
        {
            object oRes = null; //stores the final result
            try
            {
               // Assembly assembly = Assembly.Load("");
                //    Type type = Type.GetType(className);
                //    if (type.IsClass)
                //    {
                //        if (type.GetMethod(methodName) != null)
                //        {
                //            object oClass = Activator.CreateInstance(type);
                //            MethodInfo method = type.GetMethod(methodName);
                //            oRes = method.Invoke(method, args);
                //        }
                //    }
                //}
                //catch (Exception ex)
                //{
                //    log.Log(Level.SEVERE, "doIt");
                //}
                return oRes;
            }
            catch
            {
            }

            return oRes;
        }

        public Ctx GetCtx()
        {
            return ctxContext;
        }

        protected String GetName()
        {
            return _pi.GetTitle();
        }

        protected int GetAD_PInstance_ID()
        {
            return _pi.GetAD_PInstance_ID();
        }

        protected int GetTable_ID()
        {
            return _pi.GetTable_ID();
        }

        protected int GetRecord_ID()
        {
            return _pi.GetRecord_ID();
        }

        /// <summary>
        /// User ID
        /// </summary>
        /// <returns>return user id</returns>
        protected int GetAD_User_ID()
        {
            if (_pi.GetAD_User_ID() == null || _pi.GetAD_Client_ID() == null)
            {
                String sql = "SELECT AD_User_ID, AD_Client_ID FROM AD_PInstance WHERE AD_PInstance_ID=@instanceid";
                IDataReader dr = null;
                try
                {
                    SqlParameter[] param = new SqlParameter[1];
                    param[0] = new SqlParameter("@instanceid", _pi.GetAD_PInstance_ID());
                    dr = DB.ExecuteReader(sql, param);
                    while (dr.Read())
                    {
                        _pi.SetAD_User_ID(Utility.Util.GetValueOfInt(dr[0].ToString()));
                        _pi.SetAD_Client_ID(Utility.Util.GetValueOfInt(dr[1].ToString()));
                    }
                    dr.Close();
                }
                catch (Exception e)
                {
                    if (dr != null)
                    {
                        dr.Close();
                    }
                    log.Log(Level.SEVERE, sql);
                }
            }
            if (_pi.GetAD_User_ID() == 0)
                return 0;
            return (int)_pi.GetAD_User_ID();
        }

        /// <summary>
        /// Gets the client id
        /// </summary>
        /// <returns>return client id </returns>
        protected int GetAD_Client_ID()
        {
            if (_pi.GetAD_Client_ID() == null)
            {
                GetAD_User_ID();	//	Sets also Client
                if (_pi.GetAD_Client_ID() == null)
                    return 0;
            }
            return (int)_pi.GetAD_Client_ID();
        }
    }
}
